#include "mainwidget.h"

#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QGridLayout>

#include "debug.h"
#include "sessionfriendarea.h"
#include "selfinfowidget.h"
#include "sessiondetailwidget.h"
#include "groupsessiondetailwidget.h"
#include "addfrienddialog.h"
#include "model/datacenter.h"
#include "toast.h"
#include "network/netclient.h"


using namespace model;

MainWidget* MainWidget::instance = nullptr;

MainWidget::MainWidget(QWidget *parent)
    : QWidget(parent)
{
    this->setWindowTitle("我的聊天室");
    this->setWindowIcon(QIcon(":/resource/image/logo.png"));
    resize(800, 600);
    // 初始化主窗口
    initMainWindow();
    // 初始化左侧窗口布局
    initLeftWindow();
    // 初始化中间窗口布局
    initMidWindow();
    // 初始化右侧窗口布局
    initRightWindow();

    // 初始化信号槽
    initSignalSlot();

    // 初始化websocket
    initWebsocket();
}

MainWidget::~MainWidget() {}


MainWidget* MainWidget::getInstance()
{
    if(instance == nullptr){
        instance = new MainWidget();
    }

    return instance;
}

void MainWidget::initMainWindow()
{
    //水平布局
    QHBoxLayout* layout = new QHBoxLayout();
    //setSpacing 让间隔变为0
    layout->setSpacing(0);
    // 让layout 周围紧挨着
    layout->setContentsMargins(0,0,0,0);
    this->setLayout(layout);

    windowLeft = new QWidget();
    windowMid = new QWidget();
    windowRight = new QWidget();

    windowLeft->setFixedWidth(70);
    windowMid->setFixedWidth(310);
    windowRight->setMinimumWidth(800);

    windowLeft->setStyleSheet("QWidget {background-color: rgb(46,46,46);}");
    windowMid->setStyleSheet("QWidget {background-color: rgb(247,247,247);}");
    windowRight->setStyleSheet("QWidget {background-color: rgb(240,240,240);}");

    layout->addWidget(windowLeft);
    layout->addWidget(windowMid);
    layout->addWidget(windowRight);

}

void MainWidget::initLeftWindow()
{
    QVBoxLayout* layout = new QVBoxLayout();
    windowLeft->setLayout(layout);
    layout->setSpacing(20);
    //给上方留一点空间，好看  左上右下
    layout->setContentsMargins(0,50,0,0);


    //添加用户头像
    UserAvatar = new QPushButton();
    UserAvatar->setFixedSize(45,45);
    UserAvatar->setIconSize(QSize(45,45));
    //UserAvatar->setIcon(QIcon(":/resource/image/avatar.png"));
    UserAvatar->setStyleSheet("QWidget {background-color: transparent;}");
    layout->addWidget(UserAvatar,1,Qt::AlignTop | Qt::AlignCenter);

    //会话标签页
    sessionTabBtn = new QPushButton();
    sessionTabBtn->setFixedSize(45,45);
    sessionTabBtn->setIconSize(QSize(25,25));
    sessionTabBtn->setIcon(QIcon(":/resource/image/session_active.png"));
    sessionTabBtn->setStyleSheet("QWidget {background-color: transparent;}");
    layout->addWidget(sessionTabBtn,1,Qt::AlignTop | Qt::AlignCenter);

    //好友标签页
    friendtabBtn = new QPushButton();
    friendtabBtn->setFixedSize(45,45);
    friendtabBtn->setIconSize(QSize(25,25));
    friendtabBtn->setIcon(QIcon(":/resource/image/friend_inactive.png"));
    friendtabBtn->setStyleSheet("QWidget {background-color: transparent;}");
    layout->addWidget(friendtabBtn,1,Qt::AlignTop | Qt::AlignCenter);

    //好友申请
    applyTabBtn = new QPushButton();
    applyTabBtn->setFixedSize(45,45);
    applyTabBtn->setIconSize(QSize(25,25));
    applyTabBtn->setIcon(QIcon(":/resource/image/apply_inactive.png"));
    applyTabBtn->setStyleSheet("QWidget {background-color: transparent;}");
    layout->addWidget(applyTabBtn,1,Qt::AlignTop | Qt::AlignCenter);

    //在下面添加空白区域，目的是将上面的图像推到顶部
    layout->addStretch(20);
}

void MainWidget::initMidWindow()
{
    QGridLayout* layout = new QGridLayout();
    //距离上方有20的距离
    layout->setContentsMargins(0,10,0,0);
    layout->setHorizontalSpacing(10);
    layout->setVerticalSpacing(5);
    windowMid->setLayout(layout);

    // 创建搜索框
    searchEdit = new QLineEdit();
    searchEdit->setFixedHeight(25);
    searchEdit->setPlaceholderText("搜索");

    // 创建搜索图标并设置为 QLineEdit 背景图标
    searchEdit->setStyleSheet(
        "QLineEdit {"
        "border-radius: 5px;"
        "background-color: rgb(226, 226, 226);"
        "}"
        );
    searchEdit->setAlignment(Qt::AlignLeft);

    // 创建搜索图标的 QAction
    QAction* searchIconAction = new QAction();
    searchIconAction->setIcon(QIcon(":/resource/image/search_icon.png"));
    searchIconAction->setIconVisibleInMenu(true);

    // 将图标添加到 QLineEdit 的前面
    // addAction用于在QLineEdit控件的文本输入框中添加一个动作(比如 图标或者按钮)
    searchEdit->addAction(searchIconAction, QLineEdit::LeadingPosition);


    //添加加号按钮
    addFriendBtn = new QPushButton();
    addFriendBtn->setFixedSize(25,25);
    addFriendBtn->setIcon(QIcon(":/resource/image/cross.png"));
    QString style = "QPushButton { border-radius: 5px; background-color: rgb(226, 226, 226); } ";
    style += "QPushButton:pressed {background-color: rgb(240,240,240)}";
    addFriendBtn->setStyleSheet(style);

    // 因为GridLayout 不能给不同的行设置不同的边距
    // 所以用空白的区域来填充
    QWidget* space1 = new QWidget();
    space1->setFixedWidth(5);
    QWidget* space2 = new QWidget();
    space2->setFixedWidth(5);

    // 因为加载好友列表的时候，不能是栈的
    // SessionFriendArea* sessionFriendArea = new SessionFriendArea(); ERR
    sessionFriendArea = new SessionFriendArea();

    layout->addWidget(space1,0,0);
    layout->addWidget(searchEdit,0,1);
    layout->addWidget(addFriendBtn,0,2);
    layout->addWidget(space2,0,3);
    layout->addWidget(sessionFriendArea,1,0,1,4);
}

void MainWidget::initRightWindow()
{
    //创建右侧布局管理器
    QVBoxLayout* vlayout = new QVBoxLayout();
    vlayout->setContentsMargins(0,0,0,0);
    vlayout->setSpacing(0);
    vlayout->setAlignment(Qt::AlignTop);
    windowRight->setLayout(vlayout);

    //创建上方标题栏
    QWidget* titleWidget = new QWidget();
    titleWidget->setFixedHeight(62);
    titleWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
    titleWidget->setObjectName("titleWidget");
    titleWidget->setStyleSheet("#titleWidget { border-bottom: 1px solid rgb(230, 230, 230); border-left: 1px solid rgb(230, 230, 230); }");
    //将标题栏添加到布局中
    vlayout->addWidget(titleWidget);

    //给标题栏添加label 和 一个按钮
    QHBoxLayout* hlayout = new QHBoxLayout();
    hlayout->setSpacing(0);
    //让标题距离左边10 ，距离右边10
    hlayout->setContentsMargins(10,0,10,0);
    titleWidget->setLayout(hlayout);

    sessionTitleLabel = new QLabel();
    sessionTitleLabel->setStyleSheet("QLabel { font-size: 22px; border-bottom: 1px solid rgb(230, 230, 230);}");
#if TEST_UI
    sessionTitleLabel->setText("这是会话区");
#endif
    hlayout->addWidget(sessionTitleLabel);
    extraBtn = new QPushButton();
    extraBtn->setFixedSize(30,30);
    extraBtn->setIconSize(QSize(30,30));
    extraBtn->setIcon(QIcon(":/resource/image/more.png"));
    extraBtn->setStyleSheet("QPushButton { border:none; background-color: rgb(245,245,245);} QPushButton:pressed { background-color: rgb(220,220,220);}");
    hlayout->addWidget(extraBtn);

    //添加消息展示区
    messageShowArea = new MessageShowArea();
    vlayout->addWidget(messageShowArea);

    //添加消息编辑区
    messageEditArea = new MessageEditArea();
    //确保消息编辑区，位于窗口的下方
    vlayout->addWidget(messageEditArea, 0, Qt::AlignBottom);
}

// 初始化信号槽
void MainWidget::initSignalSlot()
{
    DataCenter* dataCenter = DataCenter::getInstance();

    //设置槽函数，点击不同按钮使图片高亮
    connect(sessionTabBtn,&QPushButton::clicked,this,&MainWidget::switchTabSession);
    connect(friendtabBtn,&QPushButton::clicked,this,&MainWidget::switchTabFriend);
    connect(applyTabBtn,&QPushButton::clicked,this,&MainWidget::switchTabApply);

    //点击用户按钮的时候，显示出自己的个人信息  this表示接受者是当前的对象
    connect(UserAvatar,&QPushButton::clicked,this,[=](){
        SelfInfoWidget* selfInfoWidget = new SelfInfoWidget(this);
        selfInfoWidget->exec();  // 模式对话框，会阻塞调用者，直到对话框关闭
        //selfInfoWidget->show(); // 非模式对话框
    });

    //点击会话详情按钮，弹出会话详情窗口
    connect(extraBtn,&QPushButton::clicked,this,[=](){
        //判断是单聊还是群聊
// #if TEST_GROUP_SESSION_DETAIL
//     bool isSingleChat = false;
// #else
//     bool isSingleChat = true;
// #endif
        // 找到当前会话信息
        ChatSessionInfo *chatSessionInfo = dataCenter->findChatSessionById(dataCenter->getCurrentChatSessionId());
        if(chatSessionInfo == nullptr) {
            LOG() << "当前会话不存在, 无法弹出会话详情对话框";
            return;
        }

        // 通过userId来判断，单聊是对方的userId，群聊是""
        bool isSingleChat = chatSessionInfo->userId != "";

        if(isSingleChat) {
            //单聊，弹出这个窗口
            UserInfo* userInfo = dataCenter->findFriendById(chatSessionInfo->userId);
            if (userInfo == nullptr) {
                LOG() << "单聊会话对应的用户不存在, 无法弹出会话详情窗口";
                return;
            }
            SessionDetailWidget* sessionDetailWidget = new SessionDetailWidget(this,*userInfo);
            sessionDetailWidget->exec();
        }else {
            //群聊，弹出这个窗口
            GroupSessionDetailWidget* groupSessionDetailWidget = new GroupSessionDetailWidget(chatSessionInfo->chatSessionId,chatSessionInfo->userId);
            groupSessionDetailWidget->exec();
        }
    });

    // 点击添加好友按钮，弹出可以添加好友的列表
    connect(addFriendBtn,&QPushButton::clicked,this,[=](){
        AddFriendDialog* addFriendDialog = new AddFriendDialog(this);
        addFriendDialog->exec();
    });

    // 修改搜索框的内容，弹出添加好友的对话框
    // 不能用textChanged，用户在输入框中输入就会触发或者setText修改也会触发
    // 但是textEdit只会在输入的时候触发
    connect(searchEdit,&QLineEdit::textEdited,this,[=](){
        //取出当前输入框的内容，设置到新的对话框中
        const QString& searchKey = searchEdit->text();
        AddFriendDialog* addFriendDialog = new AddFriendDialog(this);
        addFriendDialog->setSearchKey(searchKey);
        //清空主窗口的对话框
        searchEdit->setText("");
        addFriendDialog->exec();
    });

    // 获取个人信息
    connect(dataCenter,&DataCenter::getMyselfDone,this,[=](){
        // 从响应中拿到对应的UserInfo结果，将头像设置进去
        auto myself = dataCenter->getMyself();
        UserAvatar->setIcon(myself->avatar);
    });
    dataCenter->getMyselfAsync();

    // 获取好友列表
    loadFriendList();

    // 获取会话列表
    loadSessionList();

    // 获取好友申请列表
    loadApplyList();

    //处理修改头像
    connect(dataCenter,&DataCenter::changeAvatarDone,this,[=](){
        auto myself = dataCenter->getMyself();
        UserAvatar->setIcon(myself->avatar);
    });

    //处理删除好友
    connect(dataCenter,&DataCenter::deleteFriendDone,this,[=](){
        // 更新好友列表和会话列表
        this->updateFriendList();
        this->updateChatSessionList();
        LOG() << "删除好友完成";
    });

    // 处理清空会话
    connect(dataCenter,&DataCenter::clearCurrentSession,this,[=](){
        sessionTitleLabel->setText("");
        messageShowArea->clear();
        dataCenter->setCurrentChatSessionId("");
        LOG() << "清空当前会话完成";
    });


    // 处理添加好友申请
    connect(dataCenter, &DataCenter::addFriendApplyDone, this, [=]() {
        Toast::showMessage("好友申请已发送");
    });

    // 处理添加好友申请推送数据
    connect(dataCenter,&DataCenter::receiveFriendApplyDone,this,[=](){
        this->updateApplyList();
        Toast::showMessage("收到了新的好友申请");
    });


    // 处理同意好友申请
    connect(dataCenter,&DataCenter::acceptFriendApplyDone,this,[=](){
        this->updateApplyList();
        this->updateFriendList();
        Toast::showMessage("好友已经添加完成");
    });

    // 处理拒绝好友申请
    connect(dataCenter,&DataCenter::acceptFriendApplyDone,this,[=](){
        this->updateApplyList();
        Toast::showMessage("好友已经拒绝完成");
    });

    // 处理好友申请结果的推送数据
    connect(dataCenter,&DataCenter::receiveFriendProcessDone,this,[=](const QString& nickname,bool agree){
        if (agree) {
            // 同意
            this->updateFriendList();
            Toast::showMessage(nickname + " 已经同意了你的好友申请");
        } else {
            // 拒绝
            Toast::showMessage(nickname + " 已经拒绝了你的好友申请");
        }
    });

    // 处理创建群聊的响应信号
    connect(dataCenter,&DataCenter::createGroupChatSessionDone,this,[=](){
        Toast::showMessage("创建群聊会话请求已经发送!");
    });

    // 开始创建群聊
    connect(dataCenter, &DataCenter::receiveSessionCreateDone, this, [=]() {
        this->updateChatSessionList();
        // 通知用户, 入群
        Toast::showMessage("您被拉入到新的群聊中!");
    });


}

void MainWidget::initWebsocket()
{
    DataCenter* dataCenter = DataCenter::getInstance();
    dataCenter->initWebsocket();
}

//切换到会话标签页
void MainWidget::switchTabSession()
{
    activeTab = SESSION_LIST;
    sessionTabBtn->setIcon(QIcon(":/resource/image/session_active.png"));
    friendtabBtn->setIcon(QIcon(":/resource/image/friend_inactive.png"));
    applyTabBtn->setIcon(QIcon(":/resource/image/apply_inactive.png"));

    this->loadSessionList();
}
//切换到好友列表标签页
void MainWidget::switchTabFriend()
{
    activeTab = FRIEND_LIST;
    sessionTabBtn->setIcon(QIcon(":/resource/image/session_inactive.png"));
    friendtabBtn->setIcon(QIcon(":/resource/image/friend_active.png"));
    applyTabBtn->setIcon(QIcon(":/resource/image/apply_inactive.png"));

    this->loadFriendList();
}
//切换到好友申请标签页
void MainWidget::switchTabApply()
{
    activeTab = APPLY_LIST;
    sessionTabBtn->setIcon(QIcon(":/resource/image/session_inactive.png"));
    friendtabBtn->setIcon(QIcon(":/resource/image/friend_inactive.png"));
    applyTabBtn->setIcon(QIcon(":/resource/image/apply_active.png"));

    this->loadApplyList();
}

// 加载会话列表
void MainWidget::loadSessionList()
{
    // 判断会话列表是否在本地，如果本地，直接构造界面
    // 如果本地不存在，就从服务器上获取
    DataCenter* dataCenter = DataCenter::getInstance();
    if(dataCenter->getChatSessionList() != nullptr) {
        updateChatSessionList();
    }else {
        connect(dataCenter, &DataCenter::getChatSessionListDone, this, &MainWidget::updateChatSessionList, Qt::UniqueConnection);
        dataCenter->getChatSessionListAsync();
    }
}

// 加载好友列表
void MainWidget::loadFriendList()
{
    // 好友列表是在DataCenter中存储的
    // 如果DataCenter有数据，就加载本地
    // 如果没有，就从服务器获取
    DataCenter* dataCenter = DataCenter::getInstance();
    if(dataCenter->getFriendList() != nullptr) {
        //  从内存中加载
        updateFriendList();
    } else {
        connect(dataCenter, &DataCenter::getFriendListDone, this, &MainWidget::updateFriendList, Qt::UniqueConnection);
        dataCenter->getFriendListAsync();
    }
}

void MainWidget::updateFriendList()
{
    if (activeTab != FRIEND_LIST) {
        // 当前的标签页不是好友列表, 就不渲染任何数据到界面上
        return;
    }
    DataCenter* dataCenter = DataCenter::getInstance();
    QList<UserInfo>* friendList = dataCenter->getFriendList();

    // 清空一下之前界面上的数据.
    sessionFriendArea->clear();

    // 遍历好友列表, 添加到界面上
    for (const auto& f : *friendList) {
        sessionFriendArea->addItem(FriendItemType, f.userId, f.avatar, f.nickname, f.description);
    }
}

void MainWidget::updateChatSessionList()
{
    if (activeTab != SESSION_LIST) {
        // 当前的标签页不是会话列表, 就不渲染任何数据到界面上
        return;
    }
    DataCenter* dataCenter = DataCenter::getInstance();
    QList<ChatSessionInfo>* chatSessionList = dataCenter->getChatSessionList();

    // 清空一下之前界面上的数据.
    sessionFriendArea->clear();

    for(const auto& c : *chatSessionList)
    {
        if(c.lastMessage.messageType == TEXT_TYPE)
        {
            sessionFriendArea->addItem(SessionItemType,c.chatSessionId,c.avatar,c.chatSessionname,c.lastMessage.content);
        }else if(c.lastMessage.messageType == FILE_TYPE)
        {
            sessionFriendArea->addItem(SessionItemType, c.chatSessionId, c.avatar, c.chatSessionname, "[文件]");
        }else if(c.lastMessage.messageType == SPEECH_TYPE)
        {
            sessionFriendArea->addItem(SessionItemType, c.chatSessionId, c.avatar, c.chatSessionname, "[语音]");
        }else if(c.lastMessage.messageType == IMAGE_TYPE)
        {
            sessionFriendArea->addItem(SessionItemType, c.chatSessionId, c.avatar, c.chatSessionname, "[图片]");
        }else
        {
            LOG() << "错误的消息类型! messageType=" << c.lastMessage.messageType;
        }
    }
}

void MainWidget::updateApplyList()
{
    if (activeTab != APPLY_LIST) {
        return;
    }
    DataCenter* dataCenter = DataCenter::getInstance();
    QList<UserInfo>* applyList = dataCenter->getApplyList();

    // 清空一下之前界面上的数据.
    sessionFriendArea->clear();

    // 遍历好友列表, 添加到界面上
    for (const auto& f : *applyList) {
        // 直接把这个 UserInfo 对象添加到界面上即可, 不涉及到 PB 和 自己的结构之间的转换.
        // 此处 UserInfo 的 description 不需要填写进来. 好友申请列表中, 不显示用户的签名的 (这个位置被替换成了两个按钮)
        sessionFriendArea->addItem(ApplyItemType, f.userId, f.avatar, f.nickname, "");
    }
}

void MainWidget::updateRecentMessage(const QString &chatSessionId)
{
    // 拿到会话的最近几条消息
    DataCenter* dataCenter = DataCenter::getInstance();
    auto* recentMessageList = dataCenter->getRecentMessageList(chatSessionId);

    // 清空原来的消息
    messageShowArea->clear();

    // 将消息头插到messageShowArea
    for (int i = recentMessageList->size() - 1; i >= 0; --i) {
        const Message& message = recentMessageList->at(i);
        bool isLeft = message.sender.userId != dataCenter->getMyself()->userId;
        messageShowArea->addFrontMessage(isLeft, message);
    }

    // 设置会话标题
    ChatSessionInfo* chatSessionInfo = dataCenter->findChatSessionById(chatSessionId);
    if (chatSessionInfo != nullptr) {
        // 把会话名称显示到界面上.
        sessionTitleLabel->setText(chatSessionInfo->chatSessionname);
    }

    dataCenter->setCurrentChatSessionId(chatSessionId);

    //将滚动条设置到末尾
    messageShowArea->scrollToEndLater();
}

void MainWidget::switchSession(const QString &userId)
{
    // 找到对应的好友会话
    DataCenter* dataCenter = DataCenter::getInstance();
    ChatSessionInfo* chatSessionInfo = dataCenter->findChatSessionByUserId(userId);

    if(chatSessionInfo == nullptr) {
        LOG() << "[严重错误] 当前选中的好友, 对应的会话不存在!";
        return;
    }

    // 将对应的userId的会话放到第一个
    dataCenter->topChatSessionInfo(*chatSessionInfo);

    // 切换到会话列表标签页
    switchTabSession();

    // 加载这个会话对应的历史消息 0表示第一个会话列表标签页
    sessionFriendArea->clickItem(0);
}

void MainWidget::loadRecentMessage(const QString &chatSessionId)
{
    DataCenter* dataCenter = DataCenter::getInstance();
    if(dataCenter->getRecentMessageList(chatSessionId) != nullptr) {
        //  从内存中加载
        updateRecentMessage(chatSessionId);
    } else {
        connect(dataCenter, &DataCenter::getRecentMessageListDone, this, &MainWidget::updateRecentMessage, Qt::UniqueConnection);
        dataCenter->getRecentMessageListAsync(chatSessionId,true);
    }
}

MessageShowArea *MainWidget::getMessageShowArea()
{
    return messageShowArea;
}

void MainWidget::loadApplyList()
{
    DataCenter* dataCenter = DataCenter::getInstance();
    if(dataCenter->getApplyList() != nullptr) {
        //  从内存中加载
        updateApplyList();
    } else {
        connect(dataCenter, &DataCenter::getApplyListDone, this, &MainWidget::updateApplyList, Qt::UniqueConnection);
        dataCenter->getApplyListAsync();
    }
}


